<template>
  <div class="min-h-screen py-8 px-4 sm:px-6 lg:px-8">
    <div class="max-w-7xl mx-auto">
      <!-- 页面标题 -->
      <div class="text-center mb-12">
        <h1 class="text-4xl font-bold mb-4 tech-text">Resize Observer API</h1>
        <p class="text-gray-300 text-lg">
          监听元素尺寸变化，实现响应式布局和自适应组件
        </p>
      </div>

      <!-- 浏览器支持提示 -->
      <div v-if="!isSupported" class="tech-card mb-8 border-yellow-600">
        <div class="flex items-center mb-4">
          <i class="i-carbon-warning text-yellow-500 text-xl mr-3"></i>
          <h3 class="text-xl font-semibold text-yellow-500">浏览器支持提示</h3>
        </div>
        <p class="text-gray-300">
          您的浏览器不支持 Resize Observer API。此功能需要现代浏览器支持。
        </p>
      </div>

      <!-- 基础示例 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">基础尺寸监听</h2>
        <p class="text-gray-300 mb-6">拖动右下角调整元素大小，观察尺寸变化</p>
        
        <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
          <!-- 可调整大小的元素 -->
          <div>
            <div
              ref="resizableBox"
              class="bg-gradient-to-br from-blue-500 to-purple-600 rounded-lg p-6 text-white resize overflow-auto min-h-[200px]"
              style="resize: both;"
            >
              <h3 class="text-xl font-semibold mb-3">可调整大小的盒子</h3>
              <p class="mb-2">拖动右下角来调整大小</p>
              <div class="text-sm opacity-75">
                当前尺寸：{{ basicSize.width }} × {{ basicSize.height }}
              </div>
            </div>
          </div>

          <!-- 尺寸信息 -->
          <div class="bg-gray-800 rounded-lg p-6">
            <h3 class="text-white font-semibold mb-4">尺寸信息</h3>
            
            <div class="space-y-3">
              <div class="flex justify-between items-center">
                <span class="text-gray-400">宽度:</span>
                <span class="text-white font-semibold">{{ basicSize.width }}px</span>
              </div>
              
              <div class="flex justify-between items-center">
                <span class="text-gray-400">高度:</span>
                <span class="text-white font-semibold">{{ basicSize.height }}px</span>
              </div>
              
              <div class="flex justify-between items-center">
                <span class="text-gray-400">面积:</span>
                <span class="text-white font-semibold">{{ (basicSize.width * basicSize.height).toLocaleString() }}px²</span>
              </div>
              
              <div class="flex justify-between items-center">
                <span class="text-gray-400">宽高比:</span>
                <span class="text-white font-semibold">{{ aspectRatio }}</span>
              </div>
              
              <div class="flex justify-between items-center">
                <span class="text-gray-400">调整次数:</span>
                <span class="text-white font-semibold">{{ resizeCount }}</span>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 多元素监听 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">多元素监听</h2>
        <p class="text-gray-300 mb-6">同时监听多个元素的尺寸变化</p>
        
        <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
          <div
            v-for="(box, index) in observedBoxes"
            :key="index"
            :ref="el => setBoxRef(el, index)"
            class="bg-gray-800 rounded-lg p-6 resize overflow-auto min-h-[150px]"
            style="resize: both;"
          >
            <h4 class="text-white font-semibold mb-2">盒子 {{ index + 1 }}</h4>
            <div class="text-sm text-gray-400">
              <div>{{ box.width }} × {{ box.height }}</div>
              <div class="mt-1">调整: {{ box.resizeCount }} 次</div>
            </div>
          </div>
        </div>

        <div class="bg-gray-800 rounded-lg p-6">
          <h3 class="text-white font-semibold mb-4">统计信息</h3>
          
          <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
            <div>
              <div class="text-gray-400 text-sm mb-1">总调整次数</div>
              <div class="text-white text-2xl font-semibold">
                {{ totalResizeCount }}
              </div>
            </div>
            
            <div>
              <div class="text-gray-400 text-sm mb-1">平均宽度</div>
              <div class="text-white text-2xl font-semibold">
                {{ averageWidth }}px
              </div>
            </div>
            
            <div>
              <div class="text-gray-400 text-sm mb-1">平均高度</div>
              <div class="text-white text-2xl font-semibold">
                {{ averageHeight }}px
              </div>
            </div>
            
            <div>
              <div class="text-gray-400 text-sm mb-1">总面积</div>
              <div class="text-white text-2xl font-semibold">
                {{ totalArea.toLocaleString() }}
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 响应式文本 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">响应式文本大小</h2>
        <p class="text-gray-300 mb-6">根据容器大小自动调整文本大小</p>
        
        <div
          ref="responsiveTextBox"
          class="bg-gradient-to-br from-green-500 to-teal-600 rounded-lg p-8 resize overflow-hidden min-h-[200px] flex items-center justify-center"
          style="resize: both;"
        >
          <div
            class="text-white font-bold text-center"
            :style="{ fontSize: responsiveFontSize + 'px' }"
          >
            响应式文本
          </div>
        </div>
        
        <div class="mt-4 text-gray-300 text-sm">
          当前字体大小: {{ responsiveFontSize }}px
        </div>
      </div>

      <!-- 断点监听 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">断点监听</h2>
        <p class="text-gray-300 mb-6">根据容器宽度应用不同的样式</p>
        
        <div
          ref="breakpointBox"
          class="rounded-lg p-8 resize overflow-auto min-h-[200px] transition-colors duration-300"
          style="resize: horizontal;"
          :class="breakpointClass"
        >
          <h3 class="text-white text-2xl font-semibold mb-4">
            {{ breakpointName }}
          </h3>
          <p class="text-white opacity-90 mb-4">
            容器宽度: {{ breakpointWidth }}px
          </p>
          <div class="text-white text-sm opacity-75">
            <div>• 小屏 (< 400px): 红色背景</div>
            <div>• 中屏 (400-700px): 蓝色背景</div>
            <div>• 大屏 (> 700px): 绿色背景</div>
          </div>
        </div>
      </div>

      <!-- 性能监控 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">性能监控</h2>
        
        <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
          <div class="bg-gray-800 rounded-lg p-4">
            <div class="text-gray-400 text-sm mb-1">总观察次数</div>
            <div class="text-white text-2xl font-semibold">
              {{ performanceStats.totalObservations }}
            </div>
          </div>
          
          <div class="bg-gray-800 rounded-lg p-4">
            <div class="text-gray-400 text-sm mb-1">平均处理时间</div>
            <div class="text-white text-2xl font-semibold">
              {{ performanceStats.avgProcessTime }}ms
            </div>
          </div>
          
          <div class="bg-gray-800 rounded-lg p-4">
            <div class="text-gray-400 text-sm mb-1">监听元素数</div>
            <div class="text-white text-2xl font-semibold">
              {{ performanceStats.observedElements }}
            </div>
          </div>
          
          <div class="bg-gray-800 rounded-lg p-4">
            <div class="text-gray-400 text-sm mb-1">活跃观察器</div>
            <div class="text-white text-2xl font-semibold">
              {{ performanceStats.activeObservers }}
            </div>
          </div>
        </div>

        <div class="flex gap-3">
          <button
            @click="resetStats"
            class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg transition-colors"
          >
            <i class="i-carbon-renew mr-2"></i>
            重置统计
          </button>
        </div>
      </div>

      <!-- 实时日志 -->
      <div v-if="logs.length > 0" class="tech-card mb-8">
        <div class="flex justify-between items-center mb-6">
          <h2 class="text-2xl font-semibold text-white">尺寸变化日志</h2>
          <button
            @click="clearLogs"
            class="text-red-400 hover:text-red-300 text-sm"
          >
            <i class="i-carbon-clean mr-1"></i>
            清空日志
          </button>
        </div>

        <div class="space-y-2 max-h-64 overflow-y-auto">
          <div
            v-for="(log, index) in logs.slice().reverse()"
            :key="index"
            class="bg-gray-800 rounded-lg p-3 text-sm"
          >
            <div class="flex justify-between items-start">
              <div class="flex-1">
                <div class="text-white font-medium">{{ log.element }}</div>
                <div class="text-gray-300 mt-1">
                  {{ log.width }} × {{ log.height }}
                </div>
              </div>
              <div class="text-gray-400 text-xs">{{ log.timestamp }}</div>
            </div>
          </div>
        </div>
      </div>

      <!-- API 信息 -->
      <div class="tech-card">
        <h3 class="text-xl font-semibold mb-4 text-white">API 信息</h3>
        <div class="space-y-4 text-gray-300">
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">浏览器支持</h4>
            <p>Chrome 64+, Firefox 69+, Safari 13.1+, Edge 79+</p>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">主要方法</h4>
            <ul class="list-disc list-inside space-y-1">
              <li><code class="bg-gray-800 px-2 py-1 rounded">new ResizeObserver(callback)</code> - 创建观察器</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">observe(element)</code> - 开始观察元素</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">unobserve(element)</code> - 停止观察元素</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">disconnect()</code> - 停止所有观察</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">回调参数</h4>
            <ul class="list-disc list-inside space-y-1">
              <li><code class="bg-gray-800 px-2 py-1 rounded">contentRect</code> - 内容区域尺寸</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">borderBoxSize</code> - 边框盒尺寸</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">contentBoxSize</code> - 内容盒尺寸</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">devicePixelContentBoxSize</code> - 设备像素尺寸</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">使用场景</h4>
            <ul class="list-disc list-inside space-y-1">
              <li>响应式组件和布局</li>
              <li>图表和数据可视化自适应</li>
              <li>虚拟滚动列表</li>
              <li>自适应文本大小</li>
              <li>容器查询实现</li>
              <li>动态网格布局</li>
              <li>图片懒加载和尺寸优化</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">优势</h4>
            <ul class="list-disc list-inside space-y-1 text-sm">
              <li>✅ 高性能：使用浏览器原生 API，不需要轮询</li>
              <li>✅ 精确：能准确检测到所有尺寸变化</li>
              <li>✅ 灵活：可以监听任意元素</li>
              <li>✅ 简单：API 设计简洁易用</li>
              <li>✅ 批处理：多个变化会批量处理，提高性能</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">与其他方案对比</h4>
            <div class="text-sm space-y-2">
              <div>
                <strong>vs window.resize:</strong> window.resize 只监听窗口大小变化，
                而 ResizeObserver 可以监听任意元素的尺寸变化。
              </div>
              <div>
                <strong>vs MutationObserver:</strong> MutationObserver 监听 DOM 结构变化，
                ResizeObserver 专门监听尺寸变化，性能更好。
              </div>
              <div>
                <strong>vs 轮询:</strong> 不需要定时器轮询检查，由浏览器在合适的时机触发，
                性能更优且更准确。
              </div>
            </div>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">最佳实践</h4>
            <ul class="list-disc list-inside space-y-1 text-sm">
              <li>在回调中避免执行耗时操作</li>
              <li>使用防抖或节流处理频繁的尺寸变化</li>
              <li>组件卸载时记得 disconnect 观察器</li>
              <li>避免在回调中修改被观察元素的尺寸（可能导致循环）</li>
              <li>合理使用 borderBoxSize 和 contentBoxSize</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">注意事项</h4>
            <ul class="list-disc list-inside space-y-1 text-sm text-yellow-400">
              <li>⚠️ 回调可能在元素渲染前触发</li>
              <li>⚠️ 避免在回调中修改被观察元素的尺寸</li>
              <li>⚠️ 多个尺寸变化会被批量处理</li>
              <li>⚠️ 不要忘记在不需要时断开观察</li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'

// 类型定义
interface BoxSize {
  width: number
  height: number
  resizeCount: number
}

interface Log {
  element: string
  width: number
  height: number
  timestamp: string
}

// 响应式状态
const isSupported = ref('ResizeObserver' in window)

// 基础示例
const resizableBox = ref<HTMLElement | null>(null)
const basicSize = ref({ width: 0, height: 0 })
const resizeCount = ref(0)

// 多元素监听
const observedBoxes = ref<BoxSize[]>([
  { width: 0, height: 0, resizeCount: 0 },
  { width: 0, height: 0, resizeCount: 0 },
  { width: 0, height: 0, resizeCount: 0 }
])
const boxRefs: (HTMLElement | null)[] = []

// 响应式文本
const responsiveTextBox = ref<HTMLElement | null>(null)
const responsiveFontSize = ref(32)

// 断点监听
const breakpointBox = ref<HTMLElement | null>(null)
const breakpointWidth = ref(0)

// 性能统计
const performanceStats = ref({
  totalObservations: 0,
  avgProcessTime: 0,
  observedElements: 0,
  activeObservers: 0
})
const processTimes: number[] = []

// 日志
const logs = ref<Log[]>([])

// 观察器实例
let basicObserver: ResizeObserver | null = null
let multiObserver: ResizeObserver | null = null
let textObserver: ResizeObserver | null = null
let breakpointObserver: ResizeObserver | null = null

// 计算属性
const aspectRatio = computed(() => {
  if (basicSize.value.height === 0) return '0:0'
  const ratio = basicSize.value.width / basicSize.value.height
  return `${ratio.toFixed(2)}:1`
})

const totalResizeCount = computed(() => {
  return observedBoxes.value.reduce((sum, box) => sum + box.resizeCount, 0)
})

const averageWidth = computed(() => {
  const total = observedBoxes.value.reduce((sum, box) => sum + box.width, 0)
  return Math.round(total / observedBoxes.value.length)
})

const averageHeight = computed(() => {
  const total = observedBoxes.value.reduce((sum, box) => sum + box.height, 0)
  return Math.round(total / observedBoxes.value.length)
})

const totalArea = computed(() => {
  return observedBoxes.value.reduce((sum, box) => sum + (box.width * box.height), 0)
})

const breakpointName = computed(() => {
  if (breakpointWidth.value < 400) return '小屏幕'
  if (breakpointWidth.value < 700) return '中等屏幕'
  return '大屏幕'
})

const breakpointClass = computed(() => {
  if (breakpointWidth.value < 400) return 'bg-red-600'
  if (breakpointWidth.value < 700) return 'bg-blue-600'
  return 'bg-green-600'
})

// 初始化
onMounted(() => {
  if (isSupported.value) {
    setupObservers()
    performanceStats.value.activeObservers = 4
  }
})

// 清理
onUnmounted(() => {
  disconnectAllObservers()
})

// 设置观察器
const setupObservers = () => {
  // 基础观察器
  if (resizableBox.value) {
    basicObserver = new ResizeObserver((entries) => {
      const startTime = performance.now()
      
      for (const entry of entries) {
        const width = Math.round(entry.contentRect.width)
        const height = Math.round(entry.contentRect.height)
        
        basicSize.value = { width, height }
        resizeCount.value++
        
        addLog('基础盒子', width, height)
      }
      
      updatePerformanceStats(startTime)
    })
    
    basicObserver.observe(resizableBox.value)
    performanceStats.value.observedElements++
  }

  // 多元素观察器
  multiObserver = new ResizeObserver((entries) => {
    const startTime = performance.now()
    
    for (const entry of entries) {
      const index = boxRefs.findIndex(ref => ref === entry.target)
      if (index !== -1) {
        const width = Math.round(entry.contentRect.width)
        const height = Math.round(entry.contentRect.height)
        
        observedBoxes.value[index].width = width
        observedBoxes.value[index].height = height
        observedBoxes.value[index].resizeCount++
        
        addLog(`盒子 ${index + 1}`, width, height)
      }
    }
    
    updatePerformanceStats(startTime)
  })

  // 响应式文本观察器
  if (responsiveTextBox.value) {
    textObserver = new ResizeObserver((entries) => {
      const startTime = performance.now()
      
      for (const entry of entries) {
        const width = entry.contentRect.width
        // 根据宽度调整字体大小
        responsiveFontSize.value = Math.max(16, Math.min(80, Math.round(width / 10)))
      }
      
      updatePerformanceStats(startTime)
    })
    
    textObserver.observe(responsiveTextBox.value)
    performanceStats.value.observedElements++
  }

  // 断点观察器
  if (breakpointBox.value) {
    breakpointObserver = new ResizeObserver((entries) => {
      const startTime = performance.now()
      
      for (const entry of entries) {
        breakpointWidth.value = Math.round(entry.contentRect.width)
      }
      
      updatePerformanceStats(startTime)
    })
    
    breakpointObserver.observe(breakpointBox.value)
    performanceStats.value.observedElements++
  }
}

// 设置盒子引用
const setBoxRef = (el: any, index: number) => {
  if (el) {
    boxRefs[index] = el as HTMLElement
    
    // 观察新添加的元素
    if (multiObserver && !observedBoxes.value[index].width) {
      multiObserver.observe(el as HTMLElement)
      performanceStats.value.observedElements++
    }
  }
}

// 更新性能统计
const updatePerformanceStats = (startTime: number) => {
  const processTime = performance.now() - startTime
  processTimes.push(processTime)
  
  // 只保留最近 100 次
  if (processTimes.length > 100) {
    processTimes.shift()
  }
  
  performanceStats.value.totalObservations++
  performanceStats.value.avgProcessTime = Number(
    (processTimes.reduce((a, b) => a + b, 0) / processTimes.length).toFixed(2)
  )
}

// 添加日志
const addLog = (element: string, width: number, height: number) => {
  logs.value.push({
    element,
    width,
    height,
    timestamp: new Date().toLocaleTimeString('zh-CN')
  })

  // 只保留最近 50 条
  if (logs.value.length > 50) {
    logs.value.shift()
  }
}

// 清空日志
const clearLogs = () => {
  logs.value = []
}

// 重置统计
const resetStats = () => {
  performanceStats.value.totalObservations = 0
  performanceStats.value.avgProcessTime = 0
  processTimes.length = 0
  
  resizeCount.value = 0
  observedBoxes.value.forEach(box => {
    box.resizeCount = 0
  })
}

// 断开所有观察器
const disconnectAllObservers = () => {
  if (basicObserver) {
    basicObserver.disconnect()
    basicObserver = null
  }
  
  if (multiObserver) {
    multiObserver.disconnect()
    multiObserver = null
  }
  
  if (textObserver) {
    textObserver.disconnect()
    textObserver = null
  }
  
  if (breakpointObserver) {
    breakpointObserver.disconnect()
    breakpointObserver = null
  }
  
  performanceStats.value.activeObservers = 0
}
</script>

